#include "tcp_client.h"

#if defined(__GNUC__)
    #include <arpa/inet.h>
    #include <sys/socket.h>
#elif defined(_MSC_VER)
    #if defined(_WIN32)
        #ifndef WIN32_LEAN_AND_MEAN
            #define WIN32_LEAN_AND_MEAN
        #endif //! WIN32_LEAN_AND_MEAN
        #include <Windows.h>
        #include <Winsock2.h>
        #include <process.h>
        #pragma comment(lib, "Ws2_32.lib")
        #undef WIN32_LEAN_AND_MEAN
    #endif //!_WIN32
#endif

#include <event2/util.h>
#include <stdlib.h>
#include <string.h>

TcpClient::TcpClient()
{
#if defined(_MSC_VER)
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
    m_stop = false;
}

TcpClient::~TcpClient()
{
#if defined(_MSC_VER)
    WSACleanup();
#endif
}

void TcpClient::start_client(const char *host, const int port)
{
    struct sockaddr_in sock_addr = {0};
    sock_addr.sin_family         = AF_INET;
    inet_pton(AF_INET, host, (void *)&sock_addr.sin_addr);
    sock_addr.sin_port = htons(port);

    do {
        struct event_base  *base = event_base_new();
        evutil_socket_t     fd   = socket(AF_INET, SOCK_STREAM, 0);
        struct bufferevent *bev  = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev, read_cb, nullptr, event_cb, (void *)this);
        if (bufferevent_socket_connect(bev, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
            printf("bufferevent_socket_connect error");
            bufferevent_free(bev);
            return;
        }
        bufferevent_enable(bev, EV_READ | EV_PERSIST);
        event_base_dispatch(base);

        event_base_free(base);
    } while (!m_stop);
}

void TcpClient::read_cb(struct bufferevent *bev, void *ctx)
{
    struct evbuffer *input  = bufferevent_get_input(bev);
    struct evbuffer *output = bufferevent_get_output(bev);
    size_t           len    = evbuffer_get_length(input);

    evbuffer_add_buffer(output, input);
}

void TcpClient::event_cb(struct bufferevent *bev, short events, void *ptr)
{
    if (events & BEV_EVENT_CONNECTED) {
        printf("connect to server\n");
    } else if (events & BEV_EVENT_EOF) {
        bufferevent_free(bev);
    } else if (events & BEV_EVENT_ERROR) {
        printf("%s\n", evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
        bufferevent_free(bev);
    } else if (events & BEV_EVENT_TIMEOUT) {
        bufferevent_free(bev);
    }
}
